package com.gitee.wsl.logger.compress

import com.gitee.wsl.logger.debugLog
import com.gitee.wsl.logger.disk.BaseLogDiskStrategy
import java.io.File
import java.io.FileFilter
import java.io.FileOutputStream
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream

/**
 * 压缩日志文件成为zip包
 */
class ZipLogCompressStrategy : BaseLogCompressStrategy() {

    companion object {
        private const val ZIP_SUFFIX = ".zip"

        val instance = ZipLogCompressStrategy()
    }

    override fun getCompressLogs(diskStrategy: BaseLogDiskStrategy): List<File> {
        val logDir = diskStrategy.getLogDir() //获得文件夹路径
        val currentLogName = diskStrategy.currentLogFilePath?.let { File(it).name } ?:return emptyList() //获得当前正在写入的日志文件名称

        val files = File(logDir).listFiles(FileFilter { logFile ->
            return@FileFilter (logFile.name < currentLogName
                    && (logFile.name.startsWith(diskStrategy.getLogPrefix()) && logFile.name.endsWith(diskStrategy.getLogSuffix())))
        })

       return files?.toList()?: emptyList()

    }

    override fun compressOne(diskStrategy: BaseLogDiskStrategy, logFile: File): File? {
        var fileName = logFile.name
        fileName = fileName.substring(0, fileName.lastIndexOf("."))
        val zipFileName = "${fileName}$ZIP_SUFFIX"
        return try {
            logFile.zip(logFile.parentFile!!.absolutePath + File.separator + zipFileName)
        } catch (e: Exception) {
            debugLog("压缩log异常:${fileName}")
            e.printStackTrace()
            null
        }
    }

    override fun isDeleteOriginal(): Boolean {
        return true
    }

    override fun isCompressFile(compressFile: File): Boolean {
        return compressFile.name.endsWith(ZIP_SUFFIX)
    }

}


internal fun File.zip(compressedFilePath: String? = null, clean: Boolean = false, zipExt: String = ".zip"): File {

    val filePath = (compressedFilePath?:absolutePath) + zipExt
    val targetFile = File(filePath)
    val targetParentFile = targetFile.parentFile
    if (targetParentFile == null) {
        illegalArg(filePath, "parentFile cannot be null")
    } else {
        targetParentFile.mkdirs()
    }
    val zos = ZipOutputStream(FileOutputStream(filePath))

    fun action(file: File, path: String?) {
        val entryName = if (path != null) {
            path + File.separator + file.name
        } else {
            file.name
        }
        if (file.isDirectory) {
            val childFiles = file.listFiles()
            if (childFiles == null) {
                illegalArg(file, "childFiles cannot be null")
            } else {
                childFiles.forEach { action(it, entryName) }
            }
        } else {
            zos.putNextEntry(ZipEntry(entryName))
            file.forEachBlock { buffer, bytesRead ->
                zos.write(buffer, 0, bytesRead)
            }
            zos.flush()
            zos.closeEntry()
        }
    }

    zos.use {
        action(this@zip, null)
        if (clean) {
            this@zip.deleteRecursively()
        }
    }
    return File(filePath)
}

internal fun illegalArg(argument: Any?, errorMsg: String? = null): Nothing =
    throw IllegalArgumentException(
        "Illegal argument: $argument${if (errorMsg == null) "." else ", $errorMsg."}"
    )